/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse.dataset.snort;

import nfse.NetFSE;
import nfse.NetFSERecord;
import nfse.NetFSERecordFactory;
import nfse.NetFSEUtil;
import nfse.gui.server.GUIRecordFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.RandomAccessFile;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Vector;
import java.util.GregorianCalendar;
import java.util.zip.GZIPInputStream;

public class SourcefireSyslogRecord extends NetFSERecord {

    public int sid = -1;

    public int cid = -1;

    public int sigClassID = -1;

    public int proto = -1;

    public String sigName = "";

    public int dstPort = -1;

    public int srcPort = -1;

    public long dstIP = -1;

    int priority = -1;

    String classification = "";

    String protoLine = "";

    String refLine = "";

    Vector<String> content = new Vector<String>();

    public SourcefireSyslogRecord() {

    }

    public void setDstIP(long dstIP) {
        this.dstIP = dstIP;
    }

    public int[] getIndexedFields() {
        int[] temp = { NetFSE.FIELD_START_TS, NetFSE.FIELD_DST_IP, NetFSE.FIELD_SRC_IP, NetFSE.FIELD_DST_PORT };
        return temp;
    }

    public SourcefireSyslogRecord(int sensor) {
        this.setSensorID(sensor);
    }

    public String toMultiLine() {
        StringBuilder temp = new StringBuilder("[**]");
        temp.append(" [" + this.sigClassID + ":" + cid + ":" + sid + "]");
        temp.append(" " + this.sigName + " [**]\n");
        if (classification.length() > 0 || priority != -1) {
            temp.append("[Classification: " + classification + "] [Priority: " + priority + "]\n");
        }
        temp.append(convertToSnortTS(getTimestamp()) + " " + this.getSrcAddr());
        if (srcPort != -1)
            temp.append(":" + srcPort);

        temp.append(" -> " + this.getDstAddr());
        if (dstPort != -1)
            temp.append(":" + dstPort);
        temp.append("\n");

        if (protoLine.length() > 0)
            temp.append(protoLine + "\n");

        if (refLine.length() > 0) {
            temp.append("Len: " + refLine.length() + "\n");
            temp.append(refLine + "\n");
        }

        for (int i = 0; i < content.size(); i++)
            temp.append((String) content.elementAt(i) + "\n");

        return temp.toString();
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        try {
            File f = new File(args[0]);
            if (!f.exists()) {
                System.err.println("The file specified does not exist: '" + args[0] + "'.");
                throw (new Exception());
            }

            String keyword = null;
            SourcefireSyslogRecordFactory factory = new SourcefireSyslogRecordFactory();
            NetFSERecord rec = factory.generate();
            boolean isSyslog = rec.isSyslog();
            if (isSyslog)
                keyword = args[1];

            long count = 0;
            long bad = 0;
            long good = 0;
            long start = System.currentTimeMillis();
            if (f.getName().endsWith(".gz")) {
                GZIPInputStream in = new GZIPInputStream(new FileInputStream(f));
                String recordLine = factory.getRecordLine(in);
                while (recordLine != null) {
                    try {
                        count++;
                        NetFSERecord rec2 = factory.generate(recordLine, -1);
                        if (rec2 == null)
                            throw (new Exception("The record could not be parsed"));
                        good++;
                    } catch (Exception e) {
                        bad++;

                        System.out.println("-- Start bad record --\n" + recordLine + "\n-- End bad record --");
                    }
                    recordLine = factory.getRecordLine(in);
                }
                in.close();
            } else {
                RandomAccessFile raf = new RandomAccessFile(f, "r");
                String recordLine = factory.getRecordLine(raf);
                while (recordLine != null) {
                    try {

                        boolean matches = false;
                        if (isSyslog) {
                            int tagIdx = recordLine.indexOf(keyword);
                            try {
                                int tagIdx2 = recordLine.indexOf(" ", tagIdx + keyword.length());
                                String tag = recordLine.substring(tagIdx, tagIdx2);
                                // System.out.println(tag);
                                if (tag.endsWith(":")) {
                                    matches = true;
                                    //recordLine = recordLine.substring(tagIdx2).trim();
                                }
                            } catch (Exception e) {
                                // e.printStackTrace();
                            }
                        }

                        if (!isSyslog || (isSyslog && matches)) {
                            count++;
                            NetFSERecord rec2 = factory.generate(recordLine, -1);
                            if (rec2 == null)
                                throw (new Exception("The record could not be parsed"));
                            good++;
                        }
                    } catch (Exception e) {
                        bad++;
                        e.printStackTrace();
                        System.out.println("-- Start bad record --\n" + recordLine + "\n-- End bad record --");
                    }
                    recordLine = factory.getRecordLine(raf);
                }
                raf.close();
            }
            long stop = System.currentTimeMillis();

            float sec = (float) ((stop - start) / 1000);
            if (sec == (float) 0.0)
                sec = (float) 1.0;

            System.out.println("       Records: " + NetFSEUtil.formattedInteger(count));
            System.out.println("  Good records: " + NetFSEUtil.formattedInteger(good));
            System.out.println("   Bad records: " + NetFSEUtil.formattedInteger(bad));
            System.out.println("       Seconds: " + NetFSEUtil.formattedDouble(sec));
            System.out.println("Records/Second: " + NetFSEUtil.formattedDouble(count / sec));

        } catch (Exception e) {
            System.err.println("Usage: java SnortSyslogRecordFactory /data/file/path");
            System.err.println("\tThe data file can be raw logs or gzipped (ending in .gz)");
            // e.printStackTrace();
        }
    }

    protected static Timestamp convertFromSnortTS(String snortTS) {
        // Example: 12/07/05-17:18:00.186017
        // System.out.println(snortTS);
        String[] values = snortTS.split("-");
        String[] dateValues = values[0].split("/");
        String[] timeValues = values[1].split(":");

        GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
        cal.set(Calendar.MONTH, Integer.parseInt(dateValues[0]) - 1);
        cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateValues[1]));
        if (dateValues.length == 3 && dateValues[2].length() == 2)
            cal.set(Calendar.YEAR, 2000 + Integer.parseInt(dateValues[2]));
        else if (dateValues.length == 3)
            cal.set(Calendar.YEAR, Integer.parseInt(dateValues[2]));
        cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(timeValues[0]));
        cal.set(Calendar.MINUTE, Integer.parseInt(timeValues[1]));
        cal.set(Calendar.SECOND, (int) Float.parseFloat(timeValues[2]));
        return new Timestamp(cal.getTimeInMillis());
    }

    protected static String convertToSnortTS(Timestamp ts) {
        // Return Example: 12/07-17:18:00.186017

        GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
        cal.setTimeInMillis(ts.getTime());

        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int year = cal.get(Calendar.YEAR);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);

        String temp = month + "/";
        if (day < 10)
            temp += "0";
        temp += day + "/";
        temp += year + "-";
        if (hour < 10)
            temp += "0";
        temp += hour + ":";
        if (minute < 10)
            temp += "0";
        temp += minute + ":";
        if (second < 10)
            temp += "0";
        temp += second + ".0";

        return temp;

    }

    protected static int convertFromSnortProtocol(String protocol) {
        protocol = protocol.toUpperCase().trim();
        int proto = -1;
        if (protocol.equals("UDP")) {
            proto = 17;
        } else if (protocol.equals("TCP")) {
            proto = 6;
        } else if (protocol.equals("ICMP")) {
            proto = 1;
        } else {
            int idx = protocol.indexOf("PROTO");
            if (idx == 0) {
                proto = Integer.parseInt(protocol.substring(5));
            }
        }
        return proto;
    }

    @Override
    public long getDstIP() {
        return dstIP;
    }

    @Override
    public int getDstPort() {
        return dstPort;
    }

    public int getSrcPort() {
        return srcPort;
    }

    public int getProtocol() {
        return proto;
    }

    public boolean isAlert() {
        return true;
    }
    
    @Override
    public boolean isSyslog() {
        return true;
    }

    public String getAlertMessage() {
        return this.sigName;
    }

    @Override
    public boolean hasBinary() {
        return true;
    }
}